
#include "DL_Service.h"
#include "Type_Define.h"
#include "Phy_Driver.h"
#include <math.h>
 
 //AL层会防止DL层ISDU和Page通道的冲突,所以无需LOCK保护
 
 

/***********************对外服务Service***********************/
void Service_DL_Control(uint8_t Port,ControlCode_TYPE ControlCode){
   
     if(ControlCode==PDOUTVALID){
       Command_BufferOut[Port] =0x98;
     }else{
       Command_BufferOut[Port] =0x99;
     }
    Event_DL_Control(Port);// 通知OD_Handler
    Event_DL_Control_PDOUT(Port); //通知Command_Handler
}

//Mode handler状态机状态数据
 
//向SM汇报的DL_Mode_COMLOST，本事件并不是真的COMLOST，而只是模式设置错误
void Event_DL_Mode_COMLOST_ReportToSM(uint8_t Port){
	   //待更新
	
}


//告知SM当前状态
void Service_DL_Mode_Ind(uint8_t Port,DL_ModeHandler_STATE_TYPE  Mode ){
	 //待更新
	
	
}

/************* 辅助函数***********************/

// 用于MC结构的更新，状态转换后需要
  void  MC_Struct_Process (uint8_t  Port, DL_SetMode_ValueList_StructTypeDef ValueList) {
	    
	  MC_Struct[Port].M_sequenceType=ValueList.M_sequnceType;
	  MC_Struct[Port].M_squenceTime=ValueList.M_squenceTime;
    MC_Struct[Port].ODLength=ValueList.ODLength;
    MC_Struct[Port].PDInputLength=ValueList.PDInputLength;
    MC_Struct[Port].PDOutputLength=ValueList.PDOutputLength;
	
	   MY_Update_MC_Struct(Port);
	
}
//DL_SetMode的内联函数，用于状态转换到Idle的MC的重置
 void MC_Struct_INIT(uint8_t Port){
	  MC_Struct[Port].M_sequenceType=TYPE_0;
    MC_Struct[Port].M_squenceTime=0;
	  MC_Struct[Port].ODLength=1;
	  MC_Struct[Port].PDInputLength=0;
	  MC_Struct[Port].PDOutputLength=0;
		 MY_Update_MC_Struct(Port);
	  
	
}


//此服务由SM调用
RESULT_TYPE Service_DL_SetMode(uint8_t Port,SM_DL_STATE_TYPE Mode,DL_SetMode_ValueList_StructTypeDef ValueList){
     

	//参数检查
   	if(DL_Mode_CurrentState[Port]==Idle_0&&Mode!=STARTUP){
		        
		        return PARAMETER_CONFLICT_Result; 
	   }
	
	if(DL_Mode_CurrentState[Port]==Mode_Startup_2&& Mode==INACATIVE){
	   	  
		     return PARAMETER_CONFLICT_Result;
	}
	if(DL_Mode_CurrentState[Port]==Operate_4&& Mode==PREOPERATE){
	 
		   return PARAMETER_CONFLICT_Result;
	}
	
//  MC的改变，应该在状态改变之后
//	  MC_Struct[Port].M_sequenceType=ValueList.M_sequnceType;
//	  MC_Struct[Port].M_squenceTime=ValueList.M_squenceTime;
//    MC_Struct[Port].ODLength=ValueList.ODLength;
//    MC_Struct[Port].PDInputLength=ValueList.PDInputLength;
//    MC_Struct[Port].PDOutputLength=ValueList.PDOutputLength;
//	
//	   MY_Update_MC_Struct(Port);
	
	 
	
   switch (Mode)
   {
   case   STARTUP:
	       { 
					  
           
					 if(DL_Mode_CurrentState[Port]==Operate_4){         //原状态是Operate
						       
						      Command_BufferOut[Port]=0x97;
	                Event_DL_Control(Port); //通知OD handler进入CMD状态，进而使得CH能够响应命令
						      Event_CH_DL_Write_DEVICEMODE(Port);  //通知CH做好准备
						      Event_MH_DL_Write_DEVICEMODE(Port);  //通知MH发送信息，改变从站状态
						      Event_DL_SetMode_STARTUP(Port);      //通知ModeHandler改变主站状态
						      MC_Struct_INIT(Port);                 //更新MC结构
						      
					//        CMD_IN_OPERATE[Port]=STARTUP;     //SM 自己记住发出的命令
				  //以下两个动作，在DL_MH_T34中完成，根据CMD_IN_OPERATE存储的值判断    
			       // Event_DL_SetMode_INACTIVE(Port);
						     //等状态改变后 改变MC结构
						 // MC_Struct_INIT(Port);
						  
					 }
					 else if(DL_Mode_CurrentState[Port]==PreOperate_3){   //原状态是Preoperate
						        
                  Command_BufferOut[Port]=0x97;
	                Event_DL_Control(Port); //通知OD handler进入CMD状态，进而使得CH能够响应命令
						      Event_CH_DL_Write_DEVICEMODE(Port);  //通知CH做好准备
						      Event_MH_DL_Write_DEVICEMODE(Port);  //通知MH发送信息，改变从站状态
						      Event_DL_SetMode_STARTUP(Port);      //通知ModeHandler改变主站状态
						      MC_Struct_INIT(Port); 
						 
					 }else if(DL_Mode_CurrentState[Port]==Idle_0){
						 //此时无OD通信，所以不必关心 OH CM 等
						       Event_DL_SetMode_STARTUP(Port);  
						       MC_Struct_INIT(Port);
						       
					 }else{
						      return  STATE_CONFLICT_Result;
					 }
					 
			    break;
          } //case  Startup结束
   case  PREOPERATE :
	         {   
						    
                 if(DL_Mode_CurrentState[Port]==Mode_Startup_2){  			
									      								 
									        Service_DL_Write(Port,0x00,0x9A);	//自己加的 ，通知从站进入PreOperate状态 
						             // Delay_T_Mc(Port);  前面的DL_Write已经有延时了
					                 Event_DL_SetMode_PREOPERATE(Port);		//改变主站状态
									       //等状态改变后 改变MC结构
                         		MC_Struct_Process(Port,	ValueList);						 
								 }								 
								 
								 else{
									 
									     return  STATE_CONFLICT_Result;
									 
								 }

              break;
						 
	            	 
            } //case PreOperate结束
    case OPERATE:
		        {	    
							   if(DL_Mode_CurrentState[Port]==Mode_Startup_2){
									 
									     
									      Service_DL_Write(Port,0x00,0x99);	//自己加的 ，通知从站进入Operate状态 
									       
						             //Delay_T_Mc(Port);  前面的DL_Write已经有延时了
					              Event_DL_SetMode_OPERATE(Port);	 
									 
                        //等状态改变后 改变MC结构
                       MC_Struct_Process(Port,	ValueList);				
									    
								 }
								 else if(DL_Mode_CurrentState[Port]==PreOperate_3){  
									     
    									 //PreOperate状态下接收命令字后的动作
  	                     Command_BufferOut[Port]=0x99;   //填充命令字到缓冲
	                      Event_DL_Control(Port); //通知OD handler进入CMD状态
								        Event_CH_DL_Write_DEVICEMODE(Port);  //通知CH做好准备
						            Event_MH_DL_Write_DEVICEMODE(Port);  //通知MH发送信息，改变从站状态
	                      Event_DL_SetMode_OPERATE(Port);      //改变主站的状态
						             
						           //先改变MC结构，然后改变状态
                      	MC_Struct_Process(Port,	ValueList);	
									  
								 }else{
									 
									     return PARAMETER_CONFLICT_Result;
								 }
					    break;
						 }  //Case结束
    case INACATIVE:
			       if(DL_Mode_CurrentState[Port]==PreOperate_3){
							  
							    //指令含义请参见 前面
							     Command_BufferOut[Port]=0x5A;
							     Event_DL_Control(Port);
						       Event_CH_DL_Write_DEVICEMODE(Port);  //通知CH做好准备
						       Event_MH_DL_Write_DEVICEMODE(Port);  //通知MH发送信息，改变从站状态
							    //Delay_T_Mc(Port);
							   
							     Event_DL_SetMode_INACTIVE(Port);
    							 MC_Struct_INIT(Port);
							 
						 }
						 else if(DL_Mode_CurrentState[Port]==Operate_4){
						  
							 //Operate状态下接收命令字后的动作
					       Command_BufferOut[Port]=0x5A;   //填充命令字到缓冲
	                Event_DL_Control(Port); //通知OD handler进入CMD状态
						      Event_CH_DL_Write_DEVICEMODE(Port);  //通知CH做好准备
						       Event_MH_DL_Write_DEVICEMODE(Port);  //通知MH发送信息，改变从站状态
						      Event_DL_SetMode_INACTIVE(Port);      //改变主站状态
    							 MC_Struct_INIT(Port);                     
								  
							   //以下两个动作，在DL_MH_T34中完成，根据CMD_IN_OPERATE存储的值判断     
			            //Event_DL_SetMode_INACTIVE(Port);
						     //等状态改变后 改变MC结构
						     // MC_Struct_INIT(Port);
							    
						 }
		 
          
		      
		       
          break;
   default:
       return  STATE_CONFLICT_Result;
   
   }
  
	  //向SM报告当前Mode,由状态机报告
   
	 return OK_Result;
	 
}

/***********传输的步骤及必要条件是
 *1  DL_SetMode中设定MH参数DL_MH_Param中的 Type 及 OD PDin PDout字长等信息
 *2  MY_Update_MC_Struct根据DL_MH_Param设定MC OD PDin PDout等等具体位置
 *3  Service_DL_Read（Write）  等服务中，确定MC OD的值，以及确定DL_MH_Param中MC序列的
     具体长度（读写长度不同），并调用MY_Updata_MC_Struct2来更新Buffer的输出和输入长度
 *4  在前面服务所引发的Event中，调用SendMC
 *5  SendMC 发送MCBuffer存储的数据**********/

RESULT_TYPE Service_DL_Read(uint8_t Port,uint8_t Address,uint8_t* Result){
	    
	 
    //跟新OD
    *(MC_Struct[Port].MC)=Address+0xA0; //设置MC
     MC_Struct[Port].Dirction=Direction_Read; //设置读写方向
		 *MC_Struct[Port].OD=0;
		  
     Event_DL_Read(Port);
		 Delay_T_Mc(Port); //等待MC发送完成
		 
		 //DL_Read_Cnf
		 *Result=PAGE_BufferIn[Port];
		 
     return OK_Result;		 
    
}

 

 


RESULT_TYPE Service_DL_Write(uint8_t Port,uint8_t Address,uint8_t Data){
     //参数检查
  
		 
    //更新OD
     if(DL_MH_CurrentState[Port]!=MH_Startup_2){ //当不处于StartUP状态时候,嗲用WriteParam服务
              return   Service_DL_WriteParam(Port,Address,Data); 
     }else{ //当处于StartUP状态时
			   
        *(MC_Struct[Port].MC)=Address+0x20; //设置MC
        *(MC_Struct[Port].OD)=Data;
           MC_Struct[Port].Dirction=Direction_Write;
 		         
           Event_DL_Write(Port);  
     }
		 
	    Delay_T_Mc(Port); //等待MC发送完成
		  //DL_Write_Cnf
      return OK_Result;
}


 

//经过ISDU—Handler，所以比较复杂
/***********传输的步骤及必要条件是
 *1  DL_SetMode中设定MH参数DL_MH_Param中的 Type 及 OD PDin PDout字长等信息
 *2  MY_Update_MC_Struct根据DL_MH_Param设定MC OD PDin PDout等等具体位置
 *3  Service_DL_ReadParam（Write）  等服务中，确定ISDU的Channel，Page缓冲区的数据
     并触发Event(PreOperate),或者等待ISDUTrig(Operate)
 *4  在前面服务所引发的Event中（ISDU状态机）的T中，构造OD.Req, 设定MC OD，以及DL_MH_Param中的Dircetion并发送OD 事件
 *5  在OD引发的T函数中，调用MY_Updata_MC_Struct2,设定Buffer的输入输出长度
 *5  SendMC 发送MCBuffer存储的数据**********/
RESULT_TYPE Service_DL_ReadParam(uint8_t Port,uint8_t Address){
	 
 
		 
    ISDU_PARAM[Port].ISDU_Channel=Channel_ParamRequest_Read;
    ISDU_PARAM[Port].ISDU_Trans_BOOL=ISDU_ParamRequest;
    PAGE_BufferOut[Port][0]=Address;
    Event_DL_ReadParam(Port);
	 
	  return OK_Result;
    
}

void Service_DL_ReadParam_Cnf(uint8_t Port,uint8_t Data){
 
	
}

RESULT_TYPE Service_DL_WriteParam(uint8_t Port,uint8_t Address,uint8_t Data){
	 
   
    ISDU_PARAM[Port].ISDU_Channel=Channel_ParamRequest_Write;
    ISDU_PARAM[Port].ISDU_Trans_BOOL=ISDU_ParamRequest;
    PAGE_BufferOut[Port][0]=Address;
    PAGE_BufferOut[Port][1]=Data;       
    Event_DL_WriteParam(Port);
		return OK_Result;
}

void Service_DL_WriteParam_Cnf(uint8_t Port){
	 //待更新
 
}


// 用于生成ISDU的校验码

void ComputeCHEKPDU(uint8_t * Buffer,uint8_t BufferLen){
    uint8_t Result,second;
    for(uint8_t i=0;i<BufferLen-1;i++){ 
        second=Buffer[i+1];
        Result=second^Buffer[i];
    }
    Buffer[BufferLen-1]=Result;
}


/***********传输的步骤及必要条件是
 *1  DL_SetMode中设定MH参数DL_MH_Param中的 Type 及 OD PDin PDout字长等信息
 *2  MY_Update_MC_Struct根据DL_MH_Param设定MC OD PDin PDout等等具体位置
 *3  Service_DL_ISDUTransport  等服务中，确定ISDU的Channel，ISDU缓冲区的数据
     并触发Event(PreOperate),或等待被触发ISDUTrig(Operate)
 *4  在前面服务所引发的Event中（ISDU状态机）的T中，构造OD.Req, 设定MC OD，以及DL_MH_Param中的Dircetion并发送OD 事件
 *5  在OD引发的T函数中，调用MY_Updata_MC_Struct2,设定Buffer的输入输出长度
 *5  SendMC 发送MCBuffer存储的数据**********/
RESULT_TYPE Service_DL_ISDUTransport(uint8_t Port,ISDU_ValueList_Typedef ISDU_ValueList){
  
	 ISDU_PARAM[Port].ISDU_Trans_BOOL=ISDU_DL_ISDUTransport;
   //根据Table A 13的ISDU语法构造ISDU
   uint8_t LEN;
   uint8_t I_Service;
   
   //以下为填充ISDUBufferOut
   if(ISDU_ValueList.Diriction==Direction_Write){ //如果ISDU为Write 
      
      ISDU_PARAM[Port].ISDU_Channel=Channel_ParamRequest_ISDU_Write; //标记ISDU为写
      if(ISDU_ValueList.Subindex==0){  //如果没有Subindex
          I_Service=0x01<<4; //I-Service 
            if(ISDU_ValueList.OctectStringLen<=12){  //最大总长度15
               LEN=ISDU_ValueList.OctectStringLen+3;// 加3是 I service+ INDEX+CHEKPDU三个字节
               ISDU_BufferOut[Port][0]=I_Service+LEN;
               ISDU_BufferOut[Port][1]=ISDU_ValueList.Index;
               memcpy(&ISDU_BufferOut[Port][2],ISDU_ValueList.OctectString,ISDU_ValueList.OctectStringLen);
               uint8_t CHEKPDU_LOC=ISDU_ValueList.OctectStringLen+2;
               ISDU_BufferOut[Port][CHEKPDU_LOC]=0;
              ComputeCHEKPDU(&ISDU_BufferOut[Port][0],CHEKPDU_LOC+1); //更新CHEKPDU
              ISDU_PARAM[Port].ISDUBufferOutLen=LEN;
            }else{                                    //最小总长度17
              LEN=0x01;
              ISDU_BufferOut[Port][0]=I_Service+LEN;
              ISDU_BufferOut[Port][1]=ISDU_ValueList.OctectStringLen+4; 
              ISDU_BufferOut[Port][2]=ISDU_ValueList.Index;
               memcpy(&ISDU_BufferOut[Port][3],ISDU_ValueList.OctectString,ISDU_ValueList.OctectStringLen);
               uint8_t CHEKPDU_LOC=ISDU_ValueList.OctectStringLen+3;
               ISDU_BufferOut[Port][CHEKPDU_LOC]=0;
              ComputeCHEKPDU(&ISDU_BufferOut[Port][0],CHEKPDU_LOC+1); //更新CHEKPDU
              ISDU_PARAM[Port].ISDUBufferOutLen=ISDU_ValueList.OctectStringLen+4; 
               
            }
      }

      if(ISDU_ValueList.Subindex!=0&&ISDU_ValueList.Index<=255){  //如果有Subindex,且Index为8位
          I_Service=0x02<<4; //I-Service 
          if(ISDU_ValueList.OctectStringLen<=11){  //Length用LEN即可
               LEN=ISDU_ValueList.OctectStringLen+4;// 加3是 I service+ INDEX++subIndex+CHEKPDU 4个字节
               ISDU_BufferOut[Port][0]=I_Service+LEN;
               ISDU_BufferOut[Port][1]=ISDU_ValueList.Index;
               ISDU_BufferOut[Port][2]=ISDU_ValueList.Subindex;
               memcpy(&ISDU_BufferOut[Port][3],ISDU_ValueList.OctectString,ISDU_ValueList.OctectStringLen);
               uint8_t CHEKPDU_LOC=ISDU_ValueList.OctectStringLen+3;
               ISDU_BufferOut[Port][CHEKPDU_LOC]=0;
               ComputeCHEKPDU(&ISDU_BufferOut[Port][0],CHEKPDU_LOC+1); //更新CHEKPDU
               ISDU_PARAM[Port].ISDUBufferOutLen=LEN;
          }else{
               LEN=0x01;                
               ISDU_BufferOut[Port][0]=I_Service+LEN;
               ISDU_BufferOut[Port][1]=ISDU_ValueList.OctectStringLen+5;// 加5是 I service+ExLength+ INDEX+SubINdex+CHEKPDU三个字节
               ISDU_BufferOut[Port][2]=ISDU_ValueList.Index;
               ISDU_BufferOut[Port][3]=ISDU_ValueList.Subindex;
               memcpy(&ISDU_BufferOut[Port][4],ISDU_ValueList.OctectString,ISDU_ValueList.OctectStringLen);
               uint8_t CHEKPDU_LOC=ISDU_ValueList.OctectStringLen+4;
               ISDU_BufferOut[Port][CHEKPDU_LOC]=0;
               ComputeCHEKPDU(&ISDU_BufferOut[Port][0],CHEKPDU_LOC+1); //更新CHEKPDU
               ISDU_PARAM[Port].ISDUBufferOutLen=ISDU_ValueList.OctectStringLen+5;
          }
      }
      
      if(ISDU_ValueList.Subindex!=0&&ISDU_ValueList.Index>255){ //如果有SubIndex,且Index要两个字节
          I_Service=0x03<<4;
          if(ISDU_ValueList.OctectStringLen<=10){  //Length用LEN即可
               LEN=ISDU_ValueList.OctectStringLen+5;// 加3是 I service+ INDEX1 +Index2+subIndex+CHEKPDU 5个字节
               ISDU_BufferOut[Port][0]=I_Service+LEN;
               ISDU_BufferOut[Port][1]=(uint8_t)((ISDU_ValueList.Index>>8)&0x00FF);
               ISDU_BufferOut[Port][2]=(uint8_t)ISDU_ValueList.Index;               
               ISDU_BufferOut[Port][3]=ISDU_ValueList.Subindex;
               memcpy(&ISDU_BufferOut[Port][4],ISDU_ValueList.OctectString,ISDU_ValueList.OctectStringLen);
               uint8_t CHEKPDU_LOC=ISDU_ValueList.OctectStringLen+4;
               ISDU_BufferOut[Port][CHEKPDU_LOC]=0;
               ComputeCHEKPDU(&ISDU_BufferOut[Port][0],CHEKPDU_LOC+1); //更新CHEKPDU
               ISDU_PARAM[Port].ISDUBufferOutLen=LEN;
          }else{
               LEN=0x01;                
               ISDU_BufferOut[Port][0]=I_Service+LEN;
               ISDU_BufferOut[Port][1]=ISDU_ValueList.OctectStringLen+6;// 加5是 I service+ExLength+ INDEX+SubINdex+CHEKPDU三个字节
               ISDU_BufferOut[Port][2]=(uint8_t)((ISDU_ValueList.Index>>8)&0x00FF); //Index的MSB
               ISDU_BufferOut[Port][3]=(uint8_t)ISDU_ValueList.Index; //Index的LSB
               ISDU_BufferOut[Port][4]=ISDU_ValueList.Subindex;
               memcpy(&ISDU_BufferOut[Port][5],ISDU_ValueList.OctectString,ISDU_ValueList.OctectStringLen);
               uint8_t CHEKPDU_LOC=ISDU_ValueList.OctectStringLen+5;
               ISDU_BufferOut[Port][CHEKPDU_LOC]=0;
               ComputeCHEKPDU(&ISDU_BufferOut[Port][0],CHEKPDU_LOC+1); //更新CHEKPDU
               ISDU_PARAM[Port].ISDUBufferOutLen=ISDU_ValueList.OctectStringLen+6;
          }

      }

   }else //如果ISDU为Read
   { //标记ISDU为读
     ISDU_PARAM[Port].ISDU_Channel=Channel_ParamRequest_ISDU_Read;  
      if(ISDU_ValueList.Subindex==0){
          I_Service=0x09<<4; //I-Service           
          LEN=3;// 加3是 I service+ INDEX+CHEKPDU三个字节
          ISDU_BufferOut[Port][0]=I_Service+LEN;
          ISDU_BufferOut[Port][1]=ISDU_ValueList.Index;           
          ISDU_BufferOut[Port][2]=0;
            ComputeCHEKPDU(&ISDU_BufferOut[Port][0],3); //更新CHEKPDU
            ISDU_PARAM[Port].ISDUBufferOutLen=3;
         
      }
      if(ISDU_ValueList.Subindex!=0&&ISDU_ValueList.Index<=255){
           I_Service=0x0A<<4; //I-Service           
          LEN=4;// 加3是 I service+ INDEX+CHEKPDU三个字节
          ISDU_BufferOut[Port][0]=I_Service+LEN;
          ISDU_BufferOut[Port][1]=(uint8_t) ISDU_ValueList.Index ;
          ISDU_BufferOut[Port][2]= ISDU_ValueList.Subindex;        
          ISDU_BufferOut[Port][3]=0;
         
            ComputeCHEKPDU(&ISDU_BufferOut[Port][0],4); //更新CHEKPDU
            ISDU_PARAM[Port].ISDUBufferOutLen=4;

      }
      if(ISDU_ValueList.Subindex!=0&&ISDU_ValueList.Index>255){
           I_Service=0x0B<<4; //I-Service           
          LEN=5;// 加3是 I service+ INDEX+CHEKPDU三个字节
          ISDU_BufferOut[Port][0]=I_Service+LEN;
          ISDU_BufferOut[Port][1]=(uint8_t)((ISDU_ValueList.Index>>8)&0x00FF);
          ISDU_BufferOut[Port][2]=(uint8_t)ISDU_ValueList.Index;        
          ISDU_BufferOut[Port][3]=ISDU_ValueList.Subindex;
          ISDU_BufferOut[Port][4]=0;
            ComputeCHEKPDU(&ISDU_BufferOut[Port][0],5); //更新CHEKPDU
            ISDU_PARAM[Port].ISDUBufferOutLen=5;

      }
      
   }
   Event_DL_ISDUTransport(Port);
   return OK_Result;
}



/****************************************************/

void Service_DL_ISDUTransport_Cnf(uint8_t Port){
	 
}

void Service_DL_PDOutputUpdate(uint8_t Port,uint8_t * outData,uint8_t outDataLen){
	 memcpy(outData,&PD_BufferOut[Port][0],outDataLen);
	
}


void Event_DL_Mode_COMLOST(uint8_t Port){
    //Event_Handler处理
    if(EH_STATE[Port]==EH_EventConfirmation_4||EH_STATE[Port]==EH_ReadEvent_2){
         EH_STATE[Port]=EH_Inactive_0;
         return;
    }

    //ISDU_Handler处理

    if(ISDU_STATE[Port]==ISDURequest_2){
        ISDU_STATE[Port]=ISDUError_4;
       // DL_ISDU_T12(Port);
       return;
    }
    
    

}






